/******************************************************************************/
/*! 
    NGame
    [2012]

    \namespace Game    
    \brief     Game File
*/
/******************************************************************************/
/*** Header guard ************************************************************/
#ifndef NGAME_H
#define NGAME_H

/*** Includes *****************************************************************/
//Core
#include "NeroCore\NRtti.h"

//Engine
#include "NeroEngine\NPlatform.h"
#include "NeroEngine\NEventQueue.h"
#include "NeroEngine\NEventSubscriber.h"
#include "NeroEngine\NEvent.h"
//STL
#include <vector>
/*** Forward Declarations *****************************************************/
class PhysicsWorld;

namespace Game
{
	template<class T> 
	class NResourceManager;
	class NWorld;
	class NComponent;
}

namespace Engine
{
	class NEntity;
	class NPlatform;
}
/*** Namespace ****************************************************************/
namespace Game
{
/*** Macros *******************************************************************/
/*** Constants ****************************************************************/
/*** Interface ****************************************************************/
class NGame : public Core::NRtti, public Engine::NEventSubscriber
{
	RTTI_DECLARATIONS(NGame, Core::NRtti)

public:
	/********************************************//**
	*	\brief	Default Constructor
	*	\param  - void
	*	\return - void
	***********************************************/
	NGame(void);

	/********************************************//**
	*	\brief	Deconstructor
	*	\param  - void
	*	\return - void
	***********************************************/
	virtual ~NGame(void);

	/********************************************//**
	*	\brief	Initialize this class
	*	\param  - void
	*	\return - void
	***********************************************/
	virtual void Initialize(const std::string& scene);

	/********************************************//**
	*	\brief	Denitialize this class
	*	\param  - void
	*	\return - void
	***********************************************/
	virtual void Deinitialize();;
	
	/**************************************************************************//** 
	*	\brief		
	*	\param		
	*	\return		
	******************************************************************************/
	virtual void Update(float deltaTime);

	/**************************************************************************//** 
	*	\brief		
	*	\param		
	*	\return		
	******************************************************************************/
	virtual void Render();

	virtual void PreRender();

	virtual void PostRender();
	/**************************************************************************//** 
	*	\brief		
	*	\param		
	*	\return		
	******************************************************************************/
	virtual void CreateWorld(std::string worldName);

	/********************************************//**
	*	\brief	Adds a given entity to the game world
	*	\param  entity - the entity that will be added to the game world
	*	\return - void
	***********************************************/
	void AddEntityToWorld(Engine::NEntity* entity, const std::string& name);

	NWorld* GetWorld();

	Engine::NEntity* GetEntity(const std::string& name);

	Engine::NEntity* GetEntity(const int& index);

	Engine::NEventQueue& GetEventQueue();

	virtual void Notify(Engine::NEventPublisher* aEventPublisher, float wallTime);

	virtual void EndGame();

	void SetPlatform(Engine::NPlatform* platform);

	Engine::NPlatform* GetPlatform();

	int NumberOfEntities();

	void LoadScene(std::string scene);

	bool IsClosing();

	template<typename T>
	void EnqueEvent(Engine::NEvent<T>* event);

protected:
	void InitializePlatform();

	void DeinitializePlatform();

protected:
	Engine::NEventQueue mEventQueue;
	NWorld* mWorld;
	Engine::NPlatform* mPlatform;
	int mNumEntities;
	bool mIsGameClosing;
	std::vector<Game::NComponent*> mComponentList;
	bool mIsInitialized;
};

template<typename T>
void NGame::EnqueEvent(Engine::NEvent<T>* event)
{
	mEventQueue.Enqueue(event, GetPlatform()->GetGameTime());
}

}

Game::NGame* GetGame();
#endif //GAME_H